package com.xbongbong.saas.help;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.SerialNoHelp;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.CreditCardBillInfoPojo;
import com.xbongbong.paas.pojo.dto.CreditCardBillDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.CreditCardBillEntityExt;
import com.xbongbong.saas.domain.entity.ext.CreditLimitEntityExt;
import com.xbongbong.saas.enums.CreditCardBillTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.CreditCardBillEnum;
import com.xbongbong.saas.enums.business.CreditLimitEnum;
import com.xbongbong.saas.enums.business.PaymentDistributorEnum;
import com.xbongbong.saas.model.CreditCardBillModel;
import org.apache.commons.collections4.CollectionUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author: 汪腾伟
 * @date: Created in 2021/9/10 18:20
 * @description： 信用额度的帮助类
 */
@Component
public class SaasCreditHelper {

    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private SerialNoHelp serialNoHelp;
    @Resource
    private CreditCardBillModel creditCardBillModel;

    /**
     * 过滤出有信用支付的订单
     * @param orderIds
     * @param corpid
     * @return 有信用支付的订货单
     * @throws XbbException
     */
    public List<Long> filterCreditOrderIds(List<Long> orderIds, String corpid) throws XbbException {
        // 查询订货单流水
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery(CreditCardBillEnum.getEsAttr4Keyword(CreditCardBillEnum.REF_ID), orderIds));
        boolQueryBuilder.filter(termQuery(CreditCardBillEnum.getEsAttr4Keyword(CreditCardBillEnum.TYPE), CreditCardBillTypeEnum.ORDER.getCode()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.fetchSource(new String[]{"id", "data." + CreditCardBillEnum.REF_ID.getAttr()}, null);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CREDIT_CARD_BILL.getIndex());
        searchRequest.source(sourceBuilder);
        List<PaasFormDataEntityExt> dataEntityList = paasEsModel.list(sourceBuilder, IndexTypeEnum.IDX_SAAS_CREDIT_CARD_BILL, Collections.singletonList(StringConstant.JSON_DATA), 1, orderIds.size());
        List<Long> creditOrderIds = new ArrayList<>();
        dataEntityList.forEach(item -> creditOrderIds.add(item.getData().getLong(CreditCardBillEnum.REF_ID.getAttr())));
        return creditOrderIds;
    }


    /**
     * 计算信用需要还的额度
     * @param paymentIds
     * @param corpid
     * @return
     * @throws XbbException
     */
    public BigDecimal calcCreditPayLimit(Long distributorId, List<Long> orderIds, List<Long> paymentIds, String corpid) throws XbbException {
        // 查询订货单流水
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery(CreditCardBillEnum.getEsAttr4Keyword(CreditCardBillEnum.REF_ID), orderIds));
        boolQueryBuilder.filter(termQuery(CreditCardBillEnum.getEsAttr4Keyword(CreditCardBillEnum.TYPE), CreditCardBillTypeEnum.ORDER.getCode()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        sourceBuilder.fetchSource(new String[]{"id", "data." + CreditCardBillEnum.REF_ID.getAttr()}, null);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CREDIT_CARD_BILL.getIndex());
        searchRequest.source(sourceBuilder);
        List<PaasFormDataEntityExt> dataEntityList = paasEsModel.list(sourceBuilder, IndexTypeEnum.IDX_SAAS_CREDIT_CARD_BILL, Collections.singletonList(StringConstant.JSON_DATA), 1, orderIds.size());
        List<Long> creditOrderIds = new ArrayList<>();
        dataEntityList.forEach(item -> creditOrderIds.add(item.getData().getLong(CreditCardBillEnum.REF_ID.getAttr())));

        // 查询跟信用相关的待付款
        boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + StringConstant.POINT + StringConstant.KEY_WORD, corpid));
        boolQueryBuilder.filter(termsQuery("id", paymentIds));
        boolQueryBuilder.filter(termQuery(PaymentDistributorEnum.getEsAttr4Keyword(PaymentDistributorEnum.DISTRIBUTOR), distributorId));
        boolQueryBuilder.filter(termsQuery(PaymentDistributorEnum.getEsAttr4Keyword(PaymentDistributorEnum.ORDER), creditOrderIds));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_PAYMENT.getType()));
        SumAggregationBuilder sumAggregationBuilder = AggregationBuilders.sum("agg001").field(PaymentDistributorEnum.getEsAttr4Keyword(PaymentDistributorEnum.AMOUNT));
        SearchRequest paySearchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_PAYMENT.getIndex());
        SearchSourceBuilder paySourceBuilder = new SearchSourceBuilder();
        paySourceBuilder.query(boolQueryBuilder);
        // paySourceBuilder.fetchSource(new String[]{"id", "data." + PaymentDistributorEnum.ORDER.getAttr()}, null);
        paySourceBuilder.aggregation(sumAggregationBuilder);
        paySourceBuilder.size(BasicConstant.ZERO);
        paySearchRequest.source(paySourceBuilder);
        JSONObject responseJson = xbbElasticsearchRestTemplate.getAggResponseJson(paySearchRequest);
        BigDecimal result = responseJson.getJSONObject("aggregations").getJSONObject("agg001").getBigDecimal("value");
        return result;
    }

    /**
     * 添加信用流水(信用释放，当前只有已核销、预收款核销类型回款单能释放信用)
     * 改为批量：有批量生成回款单的入口，因此需要批量释放信用
     * 参数：{"corpid":"xbbxingdemo","userId":"xing001","platform":"web","frontDev":"1","distributorMark":1,"type":1,"refId":100,"refNo":"v234324","businessType":"110","amount":100,"customerId":"307697","customerName":"经销商1010"}
     * @param creditCardBillDTO
     * @return java.lang.Integer
     * @throws XbbException
     * @since v1.0
     * @version v1.0
     */
    public void addBatchCreditCardBill(CreditCardBillDTO creditCardBillDTO) throws XbbException {
        List<CreditCardBillInfoPojo> creditCardBillInfoList = creditCardBillDTO.getCreditCardBillInfoList();
        if (CollectionUtils.isEmpty(creditCardBillInfoList)) {
            return ;
        }
        String corpid = creditCardBillDTO.getCorpid();
        Integer distributorMark = creditCardBillDTO.getDistributorMark();
        Set<Long> customerIdIn = creditCardBillInfoList.stream().map(c -> c.getCustomerId()).collect(Collectors.toSet());
        int businessType = XbbRefTypeEnum.CREDIT_CARD_BILL.getCode();
        // 获取serialNo
        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByBusinessType4Distributor(businessType, corpid, distributorMark);
        if ( Objects.isNull(paasFormExplainEntity) ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Long formId = paasFormExplainEntity.getFormId();
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMapByAttr(paasFormExplainEntity.getExplains(), CreditCardBillEnum.CREDIT_CARD_NO.getAttr());
        FieldAttrEntity fieldAttrEntity = explainMap.get(CreditCardBillEnum.CREDIT_CARD_NO.getAttr());
        String serialNo = "";
        // 查询经销商信用
        List<CreditLimitEntityExt> creditLimitEntityExtList = getCreditByCustomerIdIn(customerIdIn, corpid);
        if (CollectionUtils.isEmpty(creditLimitEntityExtList)) {
            //无经销商信用，则直接返回，不用释放
            return;
        }
        //经销商id - 该经销商信用
        Map<Long, CreditLimitEntityExt> distributorMap = creditLimitEntityExtList.stream().collect(Collectors.toMap(d -> d.getData().getLong(CreditLimitEnum.CUSTOMER_ID.getAttr()), Function.identity()));
        List<CreditCardBillEntityExt> insertList = new ArrayList<>();
        for (CreditCardBillInfoPojo infoPojo : creditCardBillInfoList) {
            Long customerId = infoPojo.getCustomerId();
            CreditLimitEntityExt creditLimitEntityExt = distributorMap.get(customerId);
            if (Objects.isNull(creditLimitEntityExt)) {
                //无该经销商的信用，则跳过
                continue;
            }
            serialNo = serialNoHelp.getSerialNo(serialNo, corpid, formId, fieldAttrEntity);
            CreditCardBillEntityExt entityExt = new CreditCardBillEntityExt();
            entityExt.setCorpid(creditCardBillDTO.getCorpid());
            entityExt.setSerialNo(serialNo);
            entityExt.setFormId(formId);
            entityExt.setAppId(paasFormExplainEntity.getAppId());
            entityExt.setMenuId(paasFormExplainEntity.getMenuId());
            entityExt.setCreatorId(creditCardBillDTO.getUserId());
            entityExt.setAddTime(DateTimeUtil.getInt());
            entityExt.setUpdateTime(DateTimeUtil.getInt());
            infoPojo.setCreatorName(creditCardBillDTO.getLoginUserName());
            entityToData(infoPojo, entityExt, creditLimitEntityExt.getId());
            insertList.add(entityExt);
        }
        if (!insertList.isEmpty()) {
            creditCardBillModel.insertBatch(insertList, false);
        }
    }

    /**
     * 通过客户id集合查询creditLimitEntityList
     * @param customerIdIn
     * @param corpid
     * @return java.util.List<com.xbongbong.saas.domain.entity.ext.CreditLimitEntityExt>
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public List<CreditLimitEntityExt> getCreditByCustomerIdIn(Collection<Long> customerIdIn, String corpid) throws XbbException {
        if (CollectionUtils.isEmpty(customerIdIn)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        String keyword = StringConstant.POINT + StringConstant.KEY_WORD;
        String dataPoint = StringConstant.JSON_DATA + StringConstant.POINT;
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID + keyword, corpid));
        boolQueryBuilder.filter(termsQuery(dataPoint + CreditLimitEnum.CUSTOMER_ID.getAttr() + keyword, customerIdIn));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CREDIT_LIMIT.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CREDIT_LIMIT.getIndex());
        searchRequest.source(sourceBuilder);
        List<PaasFormDataEntityExt> dataEntityList = paasEsModel.list(sourceBuilder, IndexTypeEnum.IDX_SAAS_CREDIT_LIMIT, Collections.singletonList(StringConstant.JSON_DATA), 1, customerIdIn.size());
        List<CreditLimitEntityExt> list = new ArrayList<>();
        for (PaasFormDataEntityExt dataEntityExt : dataEntityList) {
            CreditLimitEntityExt entityExt = new CreditLimitEntityExt();
            BeanUtil.copyProperties(dataEntityExt, entityExt);
            list.add(entityExt);
        }
        return list;
    }

    /**
     * 格式转换
     * @param creditCardBillInfoPojo
     * @return
     */
    private void entityToData(CreditCardBillInfoPojo creditCardBillInfoPojo, CreditCardBillEntityExt creditCardBillEntityExt, Long creditId) {
        JSONObject data = new JSONObject();
        data.put(CreditCardBillEnum.TYPE.getAttr(), creditCardBillInfoPojo.getType());
        data.put(CreditCardBillEnum.BUSINESS_TYPE.getAttr(), creditCardBillInfoPojo.getBusinessType());
        data.put(CreditCardBillEnum.REF_ID.getAttr(), creditCardBillInfoPojo.getRefId());
        data.put(CreditCardBillEnum.REF_NO.getAttr(), creditCardBillInfoPojo.getRefNo());
        data.put(CreditCardBillEnum.AMOUNT.getAttr(), creditCardBillInfoPojo.getAmount());
        data.put(CreditCardBillEnum.CUSTOMER_ID.getAttr(), creditCardBillInfoPojo.getCustomerId());
        data.put(CreditCardBillEnum.CUSTOMER_NAME.getAttr(), creditCardBillInfoPojo.getCustomerName());
        data.put(CreditCardBillEnum.CREDIT_ID.getAttr(), creditId);
        data.put(CreditCardBillEnum.CREATOR_ID.getAttr(), creditCardBillEntityExt.getCreatorId());
        data.put(CreditCardBillEnum.CREATOR_NAME.getAttr(), creditCardBillInfoPojo.getCreatorName());
        data.put(CreditCardBillEnum.CREATOR_IS_DISTRIBUTOR.getAttr(), creditCardBillInfoPojo.getCreatorIsDistributor());
        creditCardBillEntityExt.setData(data);
    }

}
